package cloud

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/sha1"
	"dgo/MyProj/PrjHttpClt"
	"dgo/goutils/utils"
	"encoding/base64"
	"encoding/json"
	"errors"
	"fmt"
	"gitee.com/ymofen/supervalue"
	"io"
	"regexp"
	"strings"
	"time"
)

type VxUserPojo struct {
	vxid     string
	openid   string
	nickname string
	url      string
}

// 获取access_token
func (this *PlgVxApi) Get_access_token() (accesstoken string, ers string) {

	if len(this.access_token) == 0 || this.access_token_time.Before(time.Now().Add(-time.Hour*2)) {
		//获取access_token
		access_tokenjson, err9 := PrjHttpClt.GetUrlAsJSON("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + this.appid + "&secret=" + this.appsecret)
		if err9 != nil {
			utils.Log.Warn(err9.Error())
			return
		}

		access_token_re := access_tokenjson.StringByName("access_token", "")
		errmsg := access_tokenjson.StringByName("errmsg", "")
		if errmsg != "" {
			utils.Log.Warn(errmsg)
			return "", errmsg
		}
		this.access_token = access_token_re
		this.access_token_time = time.Now()
		//fmt.Println(access_token)
	}
	return this.access_token, ""
}

// 获取用户openid列表
func (this *PlgVxApi) Get_User_Openid() (*wrapper.SuperValue, error) {
	return wrapper.NewSVFromBuf([]byte(utils.GetStrValue(this.userlst.Get("data", ""), "")))
}

// 刷新用户openid和昵称map
func (this *PlgVxApi) RefreshList() (int, string) {
	acctoken, errs := this.Get_access_token()
	if errs != "" {
		return -1, errs
	}
	//fmt.Println(acctoken)
	//获取用户列表
	json1, err1 := PrjHttpClt.PostJsonEx("https://api.weixin.qq.com/cgi-bin/user/get?access_token="+acctoken+"&next_openid=", "")
	if err1 != nil {
		utils.Log.Warn(err1.Error())
		return -1, errs
	}
	if json1 == nil {
		return -1, "微信请求openidlist返回异常！"
	}
	openid_name_list := wrapper.NewSVObject()
	//fmt.Println(json1.ValueByName("data").ForceArrayByPath("openid"))
	openidlist := json1.ValueByName("data").ForceArrayByPath("openid")
	fmt.Println("开始获取...")
	openidlist.Range(func(key string, val *wrapper.SuperValue) bool {
		//通过openid获取用户基本信息
		json2, err2 := PrjHttpClt.PostJsonEx("https://api.weixin.qq.com/cgi-bin/user/info?access_token="+acctoken+"&openid="+val.String()+"&lang=zh_CN", "")
		if err2 != nil {
			utils.Log.Warn(err2.Error())
			return true
		} else {

			tempop := wrapper.NewSVObject()
			tempop.SetKeyValues("openid", val, "nickname", json2.StringByName("nickname", ""))
			openid_name_list.ArrayAppendValue(tempop)
		}
		return true
	})
	fmt.Println("获取完成!")
	this.userlst.Set("data", openid_name_list.String())
	return 0, ""
}

// 获取xml格式中的对应key的value
func (this *PlgVxApi) getXmlstr(xmlstr string, name string) (value string) {
	valuetemp5 := strings.Split(xmlstr, name)
	if len(valuetemp5) < 2 {
		return ""
	}
	valuetemp := valuetemp5[1]
	valuetemp6 := strings.Split(valuetemp, "[")
	if len(valuetemp6) < 3 {
		return ""
	}
	valuetemp2 := valuetemp6[2]
	valuetemp7 := strings.Split(valuetemp2, "]")
	if len(valuetemp6) < 1 {
		return ""
	}
	valuetemp3 := valuetemp7[0]

	return valuetemp3
}

func (this *PlgVxApi) mobilize_refresh() {
	_, errs := this.RefreshList()
	if errs != "" {
		utils.Log.Warn(errs)
		return
	}
}

func (this *PlgVxApi) checkSignature(str1 string, str2 string, str3 string) string {
	return this.sha1str(str1 + str2 + str3)
}

// 对字符串进行SHA1哈希
func (this *PlgVxApi) sha1str(data string) string {
	t := sha1.New()
	io.WriteString(t, data)
	return fmt.Sprintf("%x", t.Sum(nil))
}

// 根据openid给用户推送消息
func (this *PlgVxApi) PushWxMsg(noticedata *wrapper.SuperValue) (code int, errp string) {

	acctoken, errs := this.Get_access_token()
	if errs != "" {
		utils.Log.Warn(errs)
		return -1, errs
	}
	//openidq := noticedata.StringByName("touser","")
	//
	//temp3 := reqdata13
	//temp3 = strings.ReplaceAll(temp3,"$timenow$",time.Now().Format("2006-01-02 15:04:05"))
	//temp3 = strings.ReplaceAll(temp3,"$openid$",openidq)
	////发送模板消息
	json, err3 := PrjHttpClt.PostJsonEx("https://api.weixin.qq.com/cgi-bin/message/template/send?access_token="+acctoken, noticedata.String())
	if err3 != nil {
		utils.Log.Warn(err3)
		return -1, err3.Error()
	}
	//fmt.Println(temp3)
	if json.StringByName("errmsg", "") != "ok" {
		utils.Log.Warn("微信公众号推送信息接口调用异常!")
		return -1, "微信公众号推送信息接口调用异常!"
	}
	return 0, ""
}

var errorCode = map[string]int{
	"illegalAppId":      -41000,
	"illegalAesKey":     -41001,
	"illegalIv":         -41002,
	"illegalBuffer":     -41003,
	"decodeBase64Error": -41004,
	"decodeJsonError":   -41005,
}

// WxBizDataCrypt represents an active WxBizDataCrypt object
type WxBizDataCrypt struct {
	AppId      string
	SessionKey string
}

type showError struct {
	errorCode int
	errorMsg  error
}

func (e showError) Error() string {
	return fmt.Sprintf("{code: %v, error: \"%v\"}", e.errorCode, e.errorMsg)
}

// Decrypt Weixin APP's AES Data
// If isJSON is true, Decrypt return JSON type.
// If isJSON is false, Decrypt return map type.
func (wxCrypt *WxBizDataCrypt) Decrypt(encryptedData string, iv string, isJSON bool) (interface{}, error) {
	sessionKey := strings.Replace(strings.TrimSpace(wxCrypt.SessionKey), " ", "+", -1)
	if len(sessionKey) != 24 {
		return nil, showError{errorCode["illegalAesKey"], errors.New("sessionKey length is error")}
	}
	aesKey, err := base64.StdEncoding.DecodeString(sessionKey)
	if err != nil {
		return nil, showError{errorCode["decodeBase64Error"], err}
	}
	iv = strings.Replace(strings.TrimSpace(iv), " ", "+", -1)
	if len(iv) != 24 {
		return nil, showError{errorCode["illegalIv"], errors.New("iv length is error")}
	}
	aesIv, err := base64.StdEncoding.DecodeString(iv)
	if err != nil {
		return nil, showError{errorCode["decodeBase64Error"], err}
	}
	encryptedData = strings.Replace(strings.TrimSpace(encryptedData), " ", "+", -1)
	aesCipherText, err := base64.StdEncoding.DecodeString(encryptedData)
	if err != nil {
		return nil, showError{errorCode["decodeBase64Error"], err}
	}
	aesPlantText := make([]byte, len(aesCipherText))

	aesBlock, err := aes.NewCipher(aesKey)
	if err != nil {
		return nil, showError{errorCode["illegalBuffer"], err}
	}

	mode := cipher.NewCBCDecrypter(aesBlock, aesIv)
	mode.CryptBlocks(aesPlantText, aesCipherText)
	aesPlantText = PKCS7UnPadding(aesPlantText)

	var decrypted map[string]interface{}

	re := regexp.MustCompile(`[^\{]*(\{.*\})[^\}]*`)
	aesPlantText = []byte(re.ReplaceAllString(string(aesPlantText), "$1"))
	err = json.Unmarshal(aesPlantText, &decrypted)
	if err != nil {
		return nil, showError{errorCode["decodeJsonError"], err}
	}

	if decrypted["watermark"].(map[string]interface{})["appid"] != wxCrypt.AppId {
		return nil, showError{errorCode["illegalAppId"], errors.New("appId is not match")}
	}

	if isJSON {
		return string(aesPlantText), nil
	}

	return decrypted, nil
}

// PKCS7UnPadding return unpadding []Byte plantText
func PKCS7UnPadding(plantText []byte) []byte {
	length := len(plantText)
	if length > 0 {
		unPadding := int(plantText[length-1])
		return plantText[:(length - unPadding)]
	}
	return plantText
}
